// 定义普通函数
function fx(value: number): string {
    return value + ''
}

console.log(typeof fx);

class FxC {
    say(fx3: (value: number) => string, name: string) {

    }

    sss(): string {
        return ''
    }
}

// 定义泛型函数
function fx2<Person>(value: Person): Person {
    return value
}

console.log(typeof fx2('4564'));
const a3 = fx2<number>(34)
const b = fx2<string>('342')
console.log(a3, b)


fx(45)

let fxc: FxC = new FxC()
fxc.say(fx, '43')

let a = [3, 4, 5, 6]
// a.forea

// --- 对泛型中参数类型进行具体的约束
// 两种约束方式，一种是在参数上直接约束，一种是extends
// 第一种：在参数上直接约束
function id<Type>(value: Type[]): Type[] {
    // 如果参数不定义成数组，则无法调用length属性 ，因为Type可以为任意属性
    console.log(value.length);
    return value
}

// 第二种：使用extends
interface s {
    length: number
}

function id2<Type extends s>(value: Type): Type {
    // extends关键字约束了 Type类型必须要用length属性，比如传一个string类型 id2('432')
    console.log(value.length);
    return value
}

id([1, 2, 3])
id2('432')
// number类型没有length属性，所以下面代码报错
// id2(3)


// 泛型的高级用法， 获取对象中key的值
// 使用keyof做约束，标识Key只能是 Type中的属性
function getValByKey<Type, Key extends keyof Type>(obj: Type, key: Key) {
    return obj[key]
}

let person = {name: '42342', age: 434}
console.log('属性值：', getValByKey(person, 'name'));
// 不能传person中没有的属性
// console.log('属性值：', getValByKey(person, 'name3'));
console.log()

// 泛型接口，在接口中的属性或者方法，都可以使用定义的泛型类型
interface IdType<Type> {
    name: Type

    sad(s: Type): Type
}

let idType: IdType<string> = {
    name: '342',
    sad(value: string) {
        console.log(value)
        return value
    }
}
console.log(idType.name);
idType.sad('5434')


// 泛型类
class GenericNumber<Type> {
    sizes: Type
    name: Type

    getSize(value: string, x: Type): Type {
        return this.sizes
    }

    constructor(name: Type) {
        this.name = name
    }
}

// 当在构造函数中传参 时， 就为泛型指定了具体的类型
let generic = new GenericNumber(34)
generic.sizes = 90
console.log(generic.getSize('423', 34));


// Partial<Type> 用来创建一个类型，将Type的所有属性设置为可选
class Person {
    name: string
    age: number
    id:number
}

type PartialPerson = Partial<Person>
// 使用原始类型创建对象，所有属性都必须填写
let person: Person = {
    name: '423',
    age: 3423,
    id:10
}
console.log(person)

// 使用Partial类型，属性不需要都填写
let partialPerson: PartialPerson = {
    name: '423'
}
console.log(partialPerson)

// 泛型工具类型readonly
type ReadOnlyPerson = Readonly<Person>
let readOnlyPerson: ReadOnlyPerson = {
    name:'只读',
    age:432,
    id:10
}
// 对象属性只读，不能再赋值了
// readOnlyPerson.name = '453'

// 指定哪些属性必填
type PickPerson = Pick<Person,'name'| 'age'>
let pickPerson: PickPerson = {
    name:'432',
    age:324
}


